package cn.study.luckyapp.activity.command;

import cm.study.config.exception.LdException;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.WeightRandom;
import cn.hutool.core.util.RandomUtil;
import cn.study.luckyapp.assembler.ActivityAssembler;
import cn.study.luckyapp.record.command.RecordAddCmdExe;
import cn.study.luckyapp.record.query.RecordListByParamQueryExe;
import cn.study.luckyclient.api.IActivityConfigService;
import cn.study.luckyclient.api.IActivityService;
import cn.study.luckyclient.dto.RecordAddCmd;
import cn.study.luckyclient.dto.data.*;
import cn.study.luckyclient.dto.query.PrizeListByParamQuery;
import cn.study.luckyclient.dto.query.RecordListByParamQuery;
import cn.study.luckydomain.activity.ActivityEntity;
import cn.study.luckydomain.activity.ActivityStatusEnum;
import cn.study.luckydomain.activity.ActivityTime;
import cn.study.luckydomain.gateway.ActivityGateway;
import cn.study.luckydomain.gateway.AwardGateway;
import cn.study.luckydomain.gateway.PrizeGateway;
import cn.study.luckydomain.prize.PrizeEntity;
import com.baomidou.mybatisplus.core.metadata.IPage;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Component
@AllArgsConstructor
@Slf4j
public class DrawCmdExe {
    private final IActivityConfigService activityConfigService;
    private final PrizeGateway prizeGateway;
    private final AwardGateway awardGateway;
    private final RecordAddCmdExe recordAddCmdExe;
    private final RecordListByParamQueryExe recordListByParamQueryExe;

    private RedisDeductionNumberExe redisDeductionNumberExe;
    public DrawResultVo execute(Long id,Long userId){
        //获取活动配置
        ActivityConfigVo activityConfigVo = activityConfigService.one(id);
        //判断活动时间是否合法
        checkActivityTime(activityConfigVo.getActivityVo());
        //校验活动规则
        checkActivityRule(userId,activityConfigVo.getRuleVoList().get(0));
        //去除奖项为空的奖项
       List<AwardVo> awardVo=deducationAwardIsNull(activityConfigVo.getAwardVo());
       //抽奖算法开始抽奖
        AwardVo award = getAward(awardVo);
        DrawResultVo drawResultVo =getDrawResult(award);
        //扣减数据库 redis
        if(deductionAwardNumber(award.getActivityId(),award.getId())==0)
        {
            return getDrawResult(null);
        }
        //删除库存并添加中奖记录
        deductionAwardNumberAndUpdateRecode(activityConfigVo,award,userId);
        //保存记录
        return drawResultVo;
    }

    private void checkActivityRule(Long userId, RuleVo ruleVo) {
        RecordListByParamQuery recordListByParamQuery = new RecordListByParamQuery();
        recordListByParamQuery.setUserId(userId);
        IPage<RecordVo> page = recordListByParamQueryExe.execute(recordListByParamQuery);
        if(page.getRecords().size()>=ruleVo.getMaxJoinNumber()){
            throw new LdException("大于最大参加次数不能参加该活动了");
        }
    }

    @Transactional
    void deductionAwardNumberAndUpdateRecode(ActivityConfigVo activityConfigVo,AwardVo awardVo,Long userId) {
        int update= deductionAwardNumber(awardVo.getId(), 1);
        RecordAddCmd recordAddCmd = new RecordAddCmd();
        recordAddCmd.setAwardId(awardVo.getId());
        recordAddCmd.setState(1);
        recordAddCmd.setUserId(userId);
        recordAddCmd.setActivityName(activityConfigVo.getActivityVo().getActivityName());
        recordAddCmd.setActivityId(activityConfigVo.getActivityVo().getId());
        recordAddCmd.setIsWinning(1);
        recordAddCmdExe.execute(recordAddCmd);
    }

    private int deductionAwardNumber(Long awardId, int i) {
        return awardGateway.deducation(awardId,i);
    }
    private Integer deductionAwardNumber(Long activityId,Long awardId){return redisDeductionNumberExe.execute(activityId,awardId);}

    private DrawResultVo getDrawResult(AwardVo award) {
        DrawResultVo drawResultVo = new DrawResultVo();
        if(award.getPrizeId()!=0&& Objects.nonNull(award.getPrizeId())){
            drawResultVo.setIsDraw(true);
            drawResultVo.setAwardName(award.getAwardName());
            PrizeListByParamQuery prizeListByParamQuery = new PrizeListByParamQuery();
            prizeListByParamQuery.setId(award.getPrizeId());
            IPage<PrizeEntity> query = prizeGateway.query(prizeListByParamQuery);
            drawResultVo.setPrizeName(query.getRecords().get(0).getPrizeName());
            return drawResultVo;
        }
        drawResultVo.setAwardName("谢谢参与");
        drawResultVo.setIsDraw(false);
        return drawResultVo;
    }

    private AwardVo getAward(List<AwardVo> awardVoList) {
        List<WeightRandom.WeightObj<AwardVo>> weightList = new ArrayList<>();
        awardVoList.forEach(item -> weightList.add(new WeightRandom.WeightObj<>(item, item.getProbability())));
        //创建带有权重的随机生成器
        WeightRandom<AwardVo> wr = RandomUtil.weightRandom(weightList);
        return wr.next();
    }

    private List<AwardVo> deducationAwardIsNull(List<AwardVo> awardVo) {
        if(CollectionUtil.isEmpty(awardVo)){
            return new ArrayList<>();
        }
        List<AwardVo> collect = awardVo.stream().filter(item -> item.getNumber() > 0 || item.getPrizeId() == 0).collect(Collectors.toList());
        return collect;
    }

    private void checkActivityTime(ActivityVo activityVo) {
        ActivityEntity activityEntity = new ActivityEntity();
        activityEntity.setTime(new ActivityTime(activityVo.getStartTime(),activityVo.getEndTime()));
        ActivityStatusEnum status = activityEntity.getTime().getStatus();
        if(!ActivityStatusEnum.START.equals(status)){
            throw new LdException(String.format("活动%s",status.getDescription()));
        }

    }
}
